package com.zhentao.aop;

import com.alibaba.fastjson.JSON;
import com.zhentao.interfaceclass.LogInterface;
import com.zhentao.mapper.SysLogMapper;
import com.zhentao.mapper.SysUserMapper;
import com.zhentao.model.admin.log.SysLog;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.util.Date;
import java.util.Objects;

import static com.zhentao.common.admin.rbac.SysAdminCommon.SYS_USER_LOGIN_CACHE_KEY_ID;

/**
 * @ClassName: AdminLog
 * @Author: 振涛教育_Q
 * @Date: 2025/1/2 16:43
 */
@Aspect
@Component
@Slf4j
public class AdminLogAop {

    @Autowired
    private StringRedisTemplate redisTemplate;
    @Resource
    private SysUserMapper sysUserMapper;
    @Resource
    private SysLogMapper logMapper;
    // 自定义类用于存储时间戳相关信息
    private static class TimeStampHolder {
        private static final ThreadLocal<Long> startTimeThreadLocal = new ThreadLocal<>();
    }

    // 定义切面
    @Pointcut("execution(* com.zhentao.controller..*.*(..))")
    public void adminLogRecord() {}

    // 前置通知，记录开始时间
    @Before("adminLogRecord()")
    public void beforeAdvice(JoinPoint joinPoint) {
        TimeStampHolder.startTimeThreadLocal.set(System.currentTimeMillis());
    }

    @After("adminLogRecord()")
    public void adminLogRecord(JoinPoint joinPoint) throws Throwable {
        log.info("admin log 执行了");
        // 获取用户id
        Long userId = Long.valueOf(Objects.requireNonNull(redisTemplate.opsForValue().get(SYS_USER_LOGIN_CACHE_KEY_ID)));
        // 获取用户账户名
        String userName = sysUserMapper.selectById(userId).getUsername();
        // 获取参数
        String params = JSON.toJSONString(joinPoint.getArgs());
        // 获取操作方法 全限定名
        String methodName = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
        // 获取方法描述
        String method = joinPoint.getSignature().getName();

        // 获取每个类的 Class对象
        Class<?> adminClass = joinPoint.getTarget().getClass();
        // 获取方法上的自定义注解中的value值
        String methodDesc = "";
        try {
            MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
            Class<?>[] parameterTypes = methodSignature.getParameterTypes();
            Method targetMethod = adminClass.getMethod(method, parameterTypes);
            if (targetMethod.isAnnotationPresent(LogInterface.class)) {
                LogInterface annotation = targetMethod.getAnnotation(LogInterface.class);
                String annotationValue = annotation.value();
                methodDesc += annotationValue;
//                log.info("自定义注解MyCustomAnnotation的value值为: {}",annotationValue);
//                System.err.println("自定义注解MyCustomAnnotation的value值为: {}"+annotationValue);
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        // 获取 ip地址
        InetAddress localHost = InetAddress.getLocalHost();
//        System.err.println("本机ip地址为："+localHost.getHostAddress());
        // 计算接口耗时
        long startTime = TimeStampHolder.startTimeThreadLocal.get();
        long endTime = System.currentTimeMillis();
        long timeConsumed = endTime - startTime;

        // 创建用户对象
        SysLog sysLog = new SysLog();
        sysLog.setUserId(userId.toString());
        sysLog.setUsername(userName);
        sysLog.setOperation(methodDesc);
        sysLog.setMethod(methodName);
        sysLog.setParams(params);
        sysLog.setIp(localHost.getHostAddress());
        sysLog.setTime((int) timeConsumed);
        sysLog.setCreateTime(new Date());
        logMapper.insert(sysLog);
        log.info("用户id：{},操作日志记录成功", userId);

        // 清理ThreadLocal中的数据，避免内存泄漏
        TimeStampHolder.startTimeThreadLocal.remove();
    }
}


